/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-09-06 14:58:00
 * @LastEditors: zhl
 * @LastEditTime: 2021-09-30 17:07:31
 * @Description: file content
 */
#include <unordered_map>

#include "MessageManager.h"
#include "dlt698_frame.h"
#include "Client-APDU.h"
#include "Security-APDU.h"
#include "dlt698_global.h"
#include "global_data_struct.h"
#include "CLogger.h"
#include "common.h"
#include "check_code.h"
#include "hex.h"
#include "Base64.hpp"
#include "ParseTask.h"
#include "dlt698_db.h"
#include "dbif.h"
#include "Parse_Packet.h"
#include "json.hpp"

using json = nlohmann::json;

#define MAX_REQUEST_OAD_NUM  200
#define PACKET_MAX_SIZE 8192
#define APDU_MAX_SIZE   8000
#define STEP_SIZE       2048

//用于存放采集到的数据内容
std::unordered_map<int64_t, std::unordered_map<std::string, std::list<std::string>>> g_dev_content;

std::mutex MessageManager::c_singleton;

MessageManager::MessageManager(std::string addr,uint8_t *lc, uint8_t sbc){
    init();
    set_scrambling_code(sbc);
    set_lead_code(lc);
}

MessageManager::MessageManager(){
    init();
}

MessageManager::~MessageManager(){
    if(NULL != c_apdu){
        free(c_apdu);
        c_apdu = NULL;
    }
    if(NULL != c_frame){
        free(c_frame);
        c_frame = NULL;
    }
    if(NULL != c_data){
        free(c_data);
        c_data = NULL;
    }
    if(NULL != c_task_params){
        delete c_task_params;
    }
}

std::shared_ptr<MessageManager> MessageManager::getInstance(){
    std::lock_guard<std::mutex> lock(c_singleton);
    static std::shared_ptr<MessageManager> v_mp = std::make_shared<MessageManager>("", (uint8_t *)NULL, 0);
    return v_mp;
}

int  MessageManager::set_lead_code(uint8_t *lc){
    c_mp.set_lead_code(lc);
    return 0;
}

int  MessageManager::set_scrambling_code(uint8_t sbc){
    c_mp.set_scrambling_code(sbc);
    return 0;
}

void MessageManager::init_frame(){
    c_mp.init();
}

void MessageManager::init_thread_pool(){
    c_tp.init(1);
}
//
void MessageManager::init(){
    //
    c_task_params = new TASK_PARAMS();
    //
    c_max_oad_num = MAX_REQUEST_OAD_NUM;
    //
    c_request_id = 0;
    //
    c_apdu = (uint8_t *)malloc(APDU_MAX_SIZE);
    c_data = (uint8_t *)malloc(APDU_MAX_SIZE);
    c_frame =  (uint8_t *)malloc(PACKET_MAX_SIZE);
    //
    c_data_len = 0;
    c_frame_len = PACKET_MAX_SIZE;
    c_apdu_len = APDU_MAX_SIZE;
    c_data_max_len = APDU_MAX_SIZE;
    //
    init_frame();  
    //
    init_thread_pool();
}
//
//用于保存交互日志
void MessageManager::save_send_log(int64_t dev_id, int64_t task_id, char *buf, int len){

    if((NULL == buf) || (1 > len)){
        return ;
    }

    int  dst_len = 2*len+1;
    char dst_buf[dst_len] = {0};
    hex_to_str((unsigned char *)buf, len, dst_buf, &dst_len);
    std::string dst_str = dst_buf;
    CLogger::getInstance()->LOG_I("devid = %lld, send: %s", dev_id, dst_buf);
    add_interaction_log(dev_id, task_id, INITIATE_REQUEST, get_timestamp(), dst_str);
}
//
void MessageManager::save_recv_log(int64_t dev_id, int64_t task_id, char *buf, int len){

    if((NULL == buf) || (1 > len)){
        return ;
    }

    int  dst_len = 2*len+1;
    char dst_buf[dst_len] = {0};
    hex_to_str((unsigned char *)buf, len, dst_buf, &dst_len);
    std::string dst_str = dst_buf;
    CLogger::getInstance()->LOG_I("devid = %lld, recv: %s", dev_id, dst_buf);
    add_interaction_log(dev_id, task_id, INITIATE_RESPONSE, get_timestamp(), dst_str);
}
//
int MessageManager::assemble_and_send_frame(std::shared_ptr<CConfigManager> cm, std::shared_ptr<TERMINAL_DEVICE> dev, TASK_PARAMS *task_params){
    if((nullptr == dev) || (NULL == task_params) || (1 > task_params->items.size())){
        return -1;
    }
    auto proto = cm->get_protocol_rule(dev->protocol_id);
    if(nullptr == proto){
        return -1;
    }
    int apdu_len = APDU_MAX_SIZE;
    c_apdu_len = APDU_MAX_SIZE;
    //组装apdu内容
    if(-1 == dev->security_data_unit){
        apdu_len = Client_APDU::getInstance()->get_request_assemble(cm, task_params, c_apdu, apdu_len);
    } else {
        apdu_len = Security_APDU::getInstance()->get_request_assemble(cm, task_params, dev, c_apdu, apdu_len);
    }
    if(1 > apdu_len){
        return -1;
    }
    std::string send_msg = "";
    c_request_id++;
    //组装698协议帧
    c_mp.set_control_code(0x43);
    c_mp.set_slave_addr(dev->slave_addr);
    int frame_len = c_mp.packet_frame(c_apdu, apdu_len, c_frame, PACKET_MAX_SIZE);
    c_frame_len = PACKET_MAX_SIZE;
    save_send_log(dev->id, task_params->task_id, (char *)c_frame, frame_len);
    int ret = c_sp->send_msg(c_frame, frame_len, c_frame, c_frame_len, proto->timeout);
    if(0 < ret){
        save_recv_log(dev->id, task_params->task_id, (char *)c_frame, c_frame_len);
        handle_msg(cm);
    } else {
        CLogger::getInstance()->LOG_W("请求串口数据异常: %d", ret);
    }
    return 0;
}
//
int MessageManager::get_max_oad_num(std::shared_ptr<CConfigManager> cm){
    int request_oad_num = 5;
    try{
        std::string str_oad_num =c_cm->get_system_config("max_oad_num");
        if(!str_oad_num.empty()){
            request_oad_num = atoi(str_oad_num.c_str());
        }
        if(5 == request_oad_num){
            request_oad_num = 200;
        }
    }catch(...){

    }
    return request_oad_num;
}
//
int  MessageManager::run(std::shared_ptr<CConfigManager> cm, 
                        SerialProxy *sp_ptr, 
                        std::shared_ptr<CMosquittoManager> mm, 
                        TASK_PARAMS *task_params){
    //
    c_cm = cm;
    c_sp = sp_ptr;
    c_mm = mm;
    if(NULL == c_task_params){
        c_task_params = new TASK_PARAMS();
    }
    *c_task_params = *task_params;
    task_params->items.clear();
    std::shared_ptr<TERMINAL_DEVICE> v_dev = cm->get_terminal_device(c_task_params->dev_id);
    if(nullptr == v_dev){
        return -1;
    }
    c_data_len = 0;
    //获取最大OAD数量
    int request_oad_num = get_max_oad_num(cm);
    if((0 == request_oad_num) || (request_oad_num > (int)c_task_params->items.size())){
        assemble_and_send_frame(cm, v_dev, c_task_params);
    }else{
        std::shared_ptr<TASK_PARAMS> v_task_params = std::make_shared<TASK_PARAMS>(); 
        v_task_params->dev = c_task_params->dev;
        v_task_params->dev_id = c_task_params->dev_id;
        v_task_params->priority = c_task_params->priority;
        v_task_params->req_id = c_task_params->req_id;
        v_task_params->task_id = c_task_params->task_id;
        v_task_params->topic = c_task_params->topic;
        v_task_params->type = c_task_params->type;
        v_task_params->cmd_source = c_task_params->cmd_source;
        int i = 0;
        for(auto tmp_item = c_task_params->items.begin(); tmp_item != c_task_params->items.end(); tmp_item++){
            i++;
            v_task_params->items.push_back(*tmp_item);
            if(i == request_oad_num){
                assemble_and_send_frame(cm, v_dev, v_task_params.get());
                v_task_params->items.clear();
                i = 0;
            }
        }
        if(0 < v_task_params->items.size()){
            assemble_and_send_frame(cm, v_dev, v_task_params.get());
            v_task_params->items.clear();
        }
    }
    return 0;
}
//
int MessageManager::send_confirm(std::shared_ptr<CConfigManager> cm, int req_id){

    auto dev = cm->get_terminal_device(c_task_params->dev_id);
    if(nullptr == dev){
        return -1;
    }
    auto proto = cm->get_protocol_rule(dev->protocol_id);
    if(nullptr == proto){
        return -1;
    }
    SEPARATE_FRAME sf;
    sf.sf.sn      = req_id;
    sf.sf.type    = 2;
    sf.sf.reserve = 0;
    int frame_len = 128;
    uint8_t frame[frame_len] = {0};
    c_frame_len = PACKET_MAX_SIZE;
    c_mp.set_control_code(0x63);
    frame_len = c_mp.packet_frame((uint8_t *)&sf.value, sizeof(sf.value), frame, frame_len);
    if(0 < frame_len){
        //
        save_send_log(c_task_params->dev_id, c_task_params->task_id, (char *)c_frame, frame_len);
        c_sp->send_msg(frame, frame_len, c_frame, c_frame_len, proto->timeout);
        if(1 > c_frame_len){
            return -1;
        }
        save_recv_log(c_task_params->dev_id, c_task_params->task_id, (char *)c_frame, c_frame_len);
        handle_msg(cm);
    }
    return 0;
}
//
int MessageManager::split_joint_data(uint8_t *data, int data_len){
    if((NULL == data) || (1 > data_len)){
        return -1;
    }
    if(data_len + c_data_len > c_data_max_len){
        if(data_len > STEP_SIZE){
            c_data_max_len = c_data_len+data_len+STEP_SIZE;
            c_data = (uint8_t *)realloc(c_data, c_data_max_len); 
        }else{
            c_data_max_len = c_data_len+STEP_SIZE;
            c_data = (uint8_t *)realloc(c_data, c_data_max_len);
        }
    }
    memcpy(c_data+c_data_len, data, data_len);
    c_data_len += data_len;
    return c_data_len;
}
//获取分帧标识
SEPARATE_FRAME MessageManager::get_sf_flag(uint8_t *apdu, int len){
    SEPARATE_FRAME sf;
    if((NULL == apdu) || (1 > len)){
        sf.value = 0;
    }else{
        sf.value = *(uint16_t *)(apdu);
    }
    return sf;
}
//此方法可再优化
int MessageManager::handle_msg(std::shared_ptr<CConfigManager> cm){

    if(1 > c_apdu_len){
        return -1;
    }
    std::pair<uint16_t, uint8_t *> pair_apdu = Parse_Packet::getInstance().get_apdu((const uint8_t *)c_frame, c_frame_len);
    
    uint8_t *apdu     = pair_apdu.second;
    uint16_t apdu_len = pair_apdu.first;
    
    int subframe_type = 0;
    try{
        std::string str_subframe_type = cm->get_system_config("subframe_type");
        if(!str_subframe_type.empty()){
            subframe_type = atoi(str_subframe_type.c_str());
        }else{
            subframe_type = 1;
        }
    }catch(...){

    }
    //1为完整apdu
    if(1 == subframe_type){
        ParseTask *task = new ParseTask(c_mm, c_task_params, (char *)apdu, apdu_len);
        c_tp.add_task(task);
    }else{
        //处理分帧
        uint8_t c = Parse_Packet::getInstance().get_frame_c((const uint8_t *)c_frame, c_frame_len);
        CLogger::getInstance()->log_i("控制码: %02X", c);
        if(1 == Parse_Packet::getInstance().get_frame_c_subframe_flag(c)){
            SEPARATE_FRAME sf = get_sf_flag(apdu, apdu_len);
            if((0 == sf.sf.type) || (3 == sf.sf.type)){
                split_joint_data(apdu+sizeof(sf.value), apdu_len-sizeof(sf.value));
                send_confirm(cm, sf.sf.sn);
            }else if(1 == sf.sf.type){
                split_joint_data(apdu+sizeof(sf.value), apdu_len-sizeof(sf.value));
                ParseTask *task = new ParseTask(c_mm, c_task_params, (char *)c_data, c_data_len);
                c_tp.add_task(task);
            }else{
                send_confirm(cm, sf.sf.sn);
            }
        } else {
            ParseTask *task = new ParseTask(c_mm, c_task_params, (char *)apdu, apdu_len);
            c_tp.add_task(task);
        }
    }
       
    return 0;
}

int MessageManager::packet_parent_frame(std::shared_ptr<CConfigManager> cm, 
                                        IModule &im, 
                                        std::shared_ptr<TERMINAL_DEVICE> pdev, 
                                        uint8_t *data, int &len){
    return 0;
}